#!/bin/bash

function clear_volatile() {
    service=$(mapper get-service /org/open_power/control/volatile)
    clearVolatileEnabled=$(busctl get-property "$service" /org/open_power/control/volatile xyz.openbmc_project.Object.Enable Enabled)
    if [[ "$clearVolatileEnabled" != "b true" ]]; then
        return 0
    fi

    PNOR_TOC_FILE="pnor.toc"
    PNOR_RO_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/ro/"
    PNOR_RW_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/rw/"
    PNOR_PRSV_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/prsv/"

    # toc partition string format:
    # partition27=HB_VOLATILE,0x02ba9000,0x02bae000,00,ECC,VOLATILE,READWRITE
    tocFilePath="${PNOR_RO_ACTIVE_PATH}${PNOR_TOC_FILE}"
    if [ ! -f "${tocFilePath}" ]; then
        tocFilePath="${PNOR_RW_ACTIVE_PATH}${PNOR_TOC_FILE}"
    fi
    mapfile -t volatiles < <(grep VOLATILE "${tocFilePath}" | grep -Eo '^partition([0-9]+)=([A-Za-z0-9_]+)')
    for (( index=0; index<${#volatiles[@]}; index++ )); do
        volatileName="$(echo "${volatiles[${index}]}" | awk -F '=' '{print $2}')"

        rwVolatile="${PNOR_RW_ACTIVE_PATH}${volatileName}"

        if [ ! -f "${PNOR_RO_ACTIVE_PATH}${volatileName}" ]; then
            echo "Clear ${volatileName} lid 81e0066f.lid"
            cp -a "${PNOR_RO_ACTIVE_PATH}81e0066f.lid" "${PNOR_PRSV_ACTIVE_PATH}"
        else
            if [ -f "${rwVolatile}" ]; then
                echo "Clear $rwVolatile"
                rm "${rwVolatile}"
            fi
            prsvVolatile="${PNOR_PRSV_ACTIVE_PATH}${volatileName}"
            if [ -f "${prsvVolatile}" ]; then
                echo "Clear $prsvVolatile"
                rm "${prsvVolatile}"
            fi
        fi
    done
    # Always reset the sensor after clearing
    busctl set-property "$service" /org/open_power/control/volatile xyz.openbmc_project.Object.Enable Enabled b false
}

function update_symlinks() {
    PNOR_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/"
    HOSTFW_ACTIVE_PATH="/var/lib/phosphor-software-manager/hostfw/"
    PNOR_RO_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/ro"
    PNOR_RO_PREFIX="/media/pnor-ro-"
    PNOR_RW_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/rw"
    PNOR_RW_PREFIX="/media/pnor-rw-"
    PNOR_PRSV_ACTIVE_PATH="/var/lib/phosphor-software-manager/pnor/prsv"
    PNOR_PRSV="/media/pnor-prsv"
    PERSISTENCE_PATH="/var/lib/obmc/openpower-pnor-code-mgmt/"
    PNOR_PATCH_LOCATION="/usr/local/share/pnor/"
    MMC_BASE_PATH="/media/hostfw"
    MMC_RO_PATH="${MMC_BASE_PATH}/running-ro"
    MMC_RUNNING_PATH="${MMC_BASE_PATH}/running"
    MMC_ALTERNATE_PATH="${MMC_BASE_PATH}/alternate"
    MMC_STAGING_PATH="${MMC_BASE_PATH}/staging"
    MMC_NVRAM_PATH="${MMC_BASE_PATH}/nvram"
    HOSTFW_RUNNING_PATH="${HOSTFW_ACTIVE_PATH}/running"
    HOSTFW_ALTERNATE_PATH="${HOSTFW_ACTIVE_PATH}/alternate"
    HOSTFW_STAGING_PATH="${HOSTFW_ACTIVE_PATH}/staging"
    HOSTFW_NVRAM_PATH="${HOSTFW_ACTIVE_PATH}/nvram"

    # Get a list of all active PNOR versions
    data="$(ls -d ${PNOR_RO_PREFIX}* 2>/dev/null)"
    mapfile -t array <<< "${data}"

    currentVersion=""
    lowestPriority=255
    for element in "${array[@]}"; do
        #Remove the PNOR_RO_PREFIX from the path to get version ID.
        versionId="${element#"${PNOR_RO_PREFIX}"}"

        # Get the priority of active versions from persistence files.
        if [[ -f "${PERSISTENCE_PATH}${versionId}" ]]; then
            data="$(grep -r "priority" "${PERSISTENCE_PATH}${versionId}")"
            priority="${data: -1}"
            if [[ priority -le lowestPriority ]]; then
                lowestPriority=${priority}
                currentVersion=${versionId}
            fi
        fi
    done

    if [ -n "$currentVersion" ]; then
        # Use active version
        roTarget="${PNOR_RO_PREFIX}${currentVersion}"
        rwTarget="${PNOR_RW_PREFIX}${currentVersion}"
        prsvTarget="${PNOR_PRSV}"
    elif [ -d "${MMC_BASE_PATH}" ]; then
        # Use eMMC
        roTarget="${MMC_RO_PATH}"
        rwTarget="${MMC_RUNNING_PATH}"
        prsvTarget="${MMC_RUNNING_PATH}"

        if [ ! -d "${HOSTFW_ACTIVE_PATH}" ]; then
            mkdir -p "${HOSTFW_ACTIVE_PATH}"
        fi
        # Symlinks used by PLDM
        if [[ $(readlink -f "${HOSTFW_RUNNING_PATH}") != "${MMC_RUNNING_PATH}" ]]; then
            rm -f ${HOSTFW_RUNNING_PATH}
            ln -sfv ${MMC_RUNNING_PATH} ${HOSTFW_RUNNING_PATH}
        fi
        if [[ $(readlink -f "${HOSTFW_ALTERNATE_PATH}") != "${MMC_ALTERNATE_PATH}" ]]; then
            rm -f ${HOSTFW_ALTERNATE_PATH}
            ln -sfv ${MMC_ALTERNATE_PATH} ${HOSTFW_ALTERNATE_PATH}
        fi
        if [[ $(readlink -f "${HOSTFW_STAGING_PATH}") != "${MMC_STAGING_PATH}" ]]; then
            rm -f ${HOSTFW_STAGING_PATH}
            ln -sfv ${MMC_STAGING_PATH} ${HOSTFW_STAGING_PATH}
        fi
        if [[ $(readlink -f "${HOSTFW_NVRAM_PATH}") != "${MMC_NVRAM_PATH}" ]]; then
            rm -f ${HOSTFW_NVRAM_PATH}
            ln -sfv ${MMC_NVRAM_PATH} ${HOSTFW_NVRAM_PATH}
        fi
    fi

    if [ ! -d "${PNOR_ACTIVE_PATH}" ]; then
        mkdir -p "${PNOR_ACTIVE_PATH}"
    fi

    # If the RW or RO active links doesn't point to the version with
    # lowest priority, then remove the symlink and create new ones.
    if [[ $(readlink -f "${PNOR_RO_ACTIVE_PATH}") != "${roTarget}" ]]; then
        rm -f ${PNOR_RO_ACTIVE_PATH}
        rm -rf ${PNOR_PATCH_LOCATION}*
        ln -sfv "${roTarget}" ${PNOR_RO_ACTIVE_PATH}
    fi

    if [[ $(readlink -f "${PNOR_RW_ACTIVE_PATH}") != "${rwTarget}" ]]; then
        rm -f ${PNOR_RW_ACTIVE_PATH}
        ln -sfv "${rwTarget}" ${PNOR_RW_ACTIVE_PATH}
    fi

    if [[ $(readlink -f "${PNOR_PRSV_ACTIVE_PATH}") != "${prsvTarget}" ]]; then
        rm -f ${PNOR_PRSV_ACTIVE_PATH}
        ln -sfv "${prsvTarget}" ${PNOR_PRSV_ACTIVE_PATH}
    fi
}

case "$1" in
    clearvolatile)
        clear_volatile
        ;;
    updatesymlinks)
        update_symlinks
        ;;
    *)
        echo "Invalid argument"
        exit 1
        ;;
esac
rc=$?
if [ ${rc} -ne 0 ]; then
    echo "$0: error ${rc}"
    exit ${rc}
fi
